#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <linux/netfilter/xt_state.h>
#include <linux/netfilter/nf_conntrack_common.h>
#include <libiptc/libiptc.h>

#define __DEBUG	printf
#define IPT_ALIGN	XT_ALIGN
#define IPT_STATE_BIT	XT_STATE_BIT

#define IPTABLES_FILTER	"filter"
#define IPT_MATCH_STATE	"state"
#define IPTABLES_FILTER_FORWARD	"FORWARD"
#define IPTC_SUCCESS	1


enum {
	CMD_PE_ERR_INTERNAL = 0,
	
};

int main( void )
{
	int ret = -1;
	int tsize,esize,msize;
	struct ipt_entry_target *target;
	struct ipt_entry_match *match;
	struct xt_state_info *state;
	struct ipt_entry *e;

	//struct iptc_handle *handle;
	struct xtc_handle *handle;

	handle=iptc_init(IPTABLES_FILTER);

	if(handle == NULL){
		ret=CMD_PE_ERR_INTERNAL;
		__DEBUG(" Can't initialize iptc handle!\n");
		goto out;
	}

	/* prepare the standard ACCEPT target */
	tsize=IPT_ALIGN(sizeof(struct ipt_entry_target))+IPT_ALIGN(sizeof(int));	
	msize=IPT_ALIGN(sizeof(struct ipt_entry_match)) + IPT_ALIGN(sizeof(struct xt_state_info));

	esize=IPT_ALIGN(sizeof(struct ipt_entry))+msize+tsize;
	e=(struct ipt_entry*)malloc(esize);

	if(e == NULL){
		ret=CMD_PE_ERR_INTERNAL;
		__DEBUG(" Can't alloc memory from system!\n" );
		goto out;
	}
	memset(e,0,esize);
	e->target_offset=esize - tsize;
	e->next_offset=esize;

	/* prepare the state match */
	match=(struct ipt_entry_match *)e->elems;

	strcpy(match->u.user.name,IPT_MATCH_STATE);
	match->u.user.match_size = msize;

	state=(struct xt_state_info *)match->data;
	state->statemask |= IPT_STATE_BIT (IP_CT_ESTABLISHED) | IPT_STATE_BIT (IP_CT_RELATED);


	/* prepare the standard ACCEPT target */
	target=(struct ipt_entry_target *)((char*)e + e->target_offset);
	strcpy(target->u.user.name,IPTC_LABEL_ACCEPT);
	target->u.user.target_size = tsize;

	
	/* add it to the kernel */	
	if(iptc_append_entry(IPTABLES_FILTER_FORWARD,e,handle) != IPTC_SUCCESS)
	{
		ret=CMD_PE_ERR_INTERNAL;
		__DEBUG(" Can't insert rule into kernel!\n" );
		goto out;
	}
	if(iptc_commit(handle) != IPTC_SUCCESS)
	{
		ret=CMD_PE_ERR_INTERNAL;
		__DEBUG(" Can't commit changes!" );
		goto out;
	}

	if(e)
		free(e);

out:
	return ret;
}
